/**
* @brief 统一驱动: GPIO 驱动的开关
 * @author 张勇 41204@qq.com
 * @date 2022-04
*/

#include "switch.h"

std_err_t unidrv_switch_init(unidrv_switch_t* dev, func_gpio_switch_t funcSwitch) {
	if(!dev || !funcSwitch) { return STD_ERR_INVALID_ARG; }
	dev->funcSwitch = funcSwitch;
	dev->offTaskId = NULL;
	dev->blinkTaskId = NULL;
	dev->blinkExOnTime = 0;
	dev->state = UNIDRV_SWITCH_OFF;
	return STD_ERR_OK;
}

bool unidrv_switch_to(unidrv_switch_t* dev, unidrv_switch_state_t state, uint32_t keepTime1, uint32_t keepTime2, uint8_t flashTimes) {
	if(!dev || !dev->funcSwitch) { return false; }
	
    // 取消之前的
	unios_task_destroy(&dev->offTaskId);
    unios_task_destroy(&dev->blinkTaskId);

    if(state == UNIDRV_SWITCH_OFF || state == UNIDRV_SWITCH_ON) {
		dev->funcSwitch(state);
		bool changed = (!dev->state == !state); dev->state = state;
        return changed;
    } 
	else if(state == UNIDRV_SWITCH_TOGGLE) {
        dev->funcSwitch(!dev->state); 
		dev->state = (unidrv_switch_state_t)(!dev->state);
		return true;
    } 
	else if(state == UNIDRV_SWITCH_BLINK) {
        unidrv_switch_blinkex(dev, keepTime1, keepTime2, flashTimes);
    }
    return false;
}

static void blinkHandler(size_t len, void* data) {
	if(len < sizeof(void*) || !data) { return; }
	unidrv_switch_t* dev = (unidrv_switch_t*)mcu_get_pointer(data);
	if(!dev || !dev->funcSwitch) { return; }
	dev->funcSwitch(UNIDRV_SWITCH_OFF);
}

void unidrv_switch_blink(unidrv_switch_t* dev, uint16_t time) {
	if(!dev || !dev->funcSwitch) { return; }
	dev->funcSwitch(UNIDRV_SWITCH_ON);
	unios_task_destroy(&dev->offTaskId);
	dev->offTaskId = unios_task_run_after(time, blinkHandler, sizeof(void*), &dev);
}

static void blinkExHandler(size_t len, void* data) {
	if(!len || !data) { return; }
	unidrv_switch_t* dev = (unidrv_switch_t*)mcu_get_pointer(data);
	if(!dev || !dev->funcSwitch) { return; }
	unidrv_switch_blink(dev, dev->blinkExOnTime);
}

unios_task_t unidrv_switch_blinkex(unidrv_switch_t* dev, uint16_t onTime, uint16_t offTime, uint16_t count) {
	// 参数检查
	if(!(dev && dev->funcSwitch && onTime && offTime && count>1)) { return NULL; }
    dev->blinkExOnTime = onTime;

    // 取消之前的
	unios_task_destroy(&dev->offTaskId);
    unios_task_destroy(&dev->blinkTaskId);

    // 先闪第一次
    unidrv_switch_blink(dev, onTime);
    if(count != UNIOS_TASK_REPEAT_FOREVER) { count--; }

	// 安排后续的闪烁
	// 注意：需要把对象的指针传过去，以便在回调函数中访问对象
	return dev->blinkTaskId = unios_task_run_every(onTime+offTime, count, blinkExHandler, sizeof(dev), &dev, false);
}
